
include 'encoding\utf8.inc'
include 'instrExA.inc'
include 'blocks32.inc'

stack 0x80000

macro _pushloop c, v
{
	local	..a
	mov	ecx, c
	..a:
		push	v
		loop	..a
}

macro _cmalloc r, t
{
	push	r
	call	[malloc]
	pop	ecx
	match	any, t
	\{
		test	eax, eax
		jz	t
	\}
}

macro _cmalloc2 r, t
{
	mov	[esp], r
	call	[malloc]
	match	any, t
	\{
		test	eax, eax
		jz	t
	\}
}

macro _cfree r, t
{
	push	r
	call	[free]
	pop	ecx
	match	any, t
	\{
		jmp	 t
	\}
}

macro _cfree2 r, t
{
	mov	[esp], r
	call	[free]
	match	any, t
	\{
		jmp	 t
	\}
}

macro callpop f, s
{
	call	f
	add	esp, s*4
}

macro rep_ret
{
	db	0xF3
	ret
}

macro ._endif_jmp l
{
	jmp	l
	.endif
}

macro _call_unwind a, b, c
{
	local ..a
	invoke	RtlUnwind, a, ..a, b, c
	..a:
}

entry start

section '.text' code readable executable

; GetCurrentProcess returns -1
; GetCurrentThread  returns -2

sizeof.CONTEXT	equ 0x2CC

HANDLE_CURRENT_PROCESS equ (-1)
HANDLE_CURRENT_THREAD  equ (-2)

STATUS_BREAKPOINT		equ 0x80000003
STATUS_SINGLE_STEP		equ 0x80000004
STATUS_ILLEGAL_INSTRUCTION	equ 0xC000001D ; invalid/ud2 instruction
STATUS_STACK_OVERFLOW		equ 0xC00000FD ; not means stack buffer overflow
STATUS_STACK_BUFFER_OVERRUN	equ 0xC0000409

_begin_of_code:
start:
	xor	ecx, ecx	; ecx is volatile register
	AlignProcEnter , ebx esi edi ecx, 0
	invoke	GetCommandLine
	push	eax
	push	NULL
	mov	ecx, esp
	call	._initialize
	cmp	dword [esp], NULL
	je	._no_mutex
   .strbuf_size equ (72*sizeof.TCHAR)
	lea	esp, [ebp-(84+32*sizeof.TCHAR+.strbuf_size)]
	lea	ecx, [local_fp-4*5]
	mov	edx, [local_fp-4]
	call	_splitcmdline2module
	jz	.release_lib_set
	mov	ecx, _libr.str_resetstkoflw
	call	_mygetlib.msvcrt
	mov	[.proc_resetstkoflw], eax
	mov	ebx, esp
	lea	esi, [._string_MYCON]
	mov	edi, ebx
	mov	ecx, 2*sizeof.TCHAR
	rep	movsd
	lea	edi, [local_fp-4*8]
	push	ebx
	stdcall _make_identifier._base, edi
	.repeat
		lea	ecx, [ebx+6*sizeof.TCHAR]
		mov	edx, edi
		call	_make_identifier
		mov	eax, edi
		lea	ecx, [local_fp-4*10]
		mov	edx, 0x6000
		call	_fMap
	.until	~CARRY?
	pop	ecx
	jz	.release_lib_set
	add	ecx, 6*sizeof.TCHAR

	lea	ebx, [esp + 32*sizeof.TCHAR]
	mov	[local_fp-4*7], eax
	mov	[local_fp-4*8], ebx
	push	ecx
	xor	esi, esi	; set esi = 0 (canary value)
	lea	edi, [ebx+.strbuf_size]
	mov	[edi], esi	; Add canary word to detecting buffer overflow
	push	_myconhost_exe__s .strbuf_size ebx
	add	ebx, .strbuf_size + 4
	callpop [sntprintf], 4
    restore	.strbuf_size
	mov	ecx, [local_fp-4*8]
	mov	edx, ebx
	neg	esi
	stc
	call	_newproc
	mov	ecx, [edi]
	lea	ecx, [ecx+esi]
	call	._test_bufferoflw.preserve_eflags
	jz	._newproc_failure
	mov	eax, [local_fp-4*2]
	call	._dup_handle_1
	test	eax, eax
	jz	._resume_proc_failure
	mov	esi, eax
	invoke	GetCurrentThread
	call	._dup_handle_1
	mov	ecx, [local_fp-4*7]
	add	ecx, 80*25*12
	call	._make_struc_1
	add	ecx, 16
	mov	edx, [ebx+4]
	call	_waitforalerted.1
	jc	._resume_proc_failure
	mov	ecx, ebx
	mov	edx, 2
	call	_closehandles
	jz	._resume_proc_failure2
	lea	eax, [local_fp-4*5]
	mov	ebx, [local_fp-4*7]
	mov	ecx, [local_fp-4*2]
	lea	edx, [local_fp]
	call	.run_routine
  .run_routine_end:
	lea	ecx, [local_fp-4*10]
	call	_fUnmap
  .release_lib:
	lea	ecx, [local_fp-4*5]
	call	_splitcmdline2module._release1
	invoke	CloseHandle, dword [local_fp-4*2]
  ._no_mutex2:
	AlignProcLeave	, norstor
	invoke	ExitProcess, ecx
	jmp	_no_return

  .release_lib_set:
	mov	dword [local_fp], 1
	jmp	.release_lib
	align	8
  ._resume_proc_failure:
	invoke	TerminateProcess, dword [ebx], -1
	mov	ecx, ebx
	mov	edx, 2
	call	_closehandles
  ._newproc_failure:
  ._resume_proc_failure2:
	mov	dword [local_fp], 1
	jmp	.run_routine_end
	align	16
  ._no_mutex:
	mov	dword [local_fp], 1
	jmp	._no_mutex2
	restore local_fp
	align	16

  ._initialize:
	; HANDLE CreateMutexA(
	;	 LPSECURITY_ATTRIBUTES lpMutexAttributes,
	;	 BOOL		       bInitialOwner,
	;	 LPCSTR 	       lpName
	; );
	push	ecx NULL FALSE NULL vSyncDllEvent
	or	dword [esp-0x1000], 0	; maybe calling __chkstk
	call	[InitializeCriticalSection]
	call	[CreateMutex]
	pop	edx
	lea	ecx, [._canary]
	mov	[edx], eax
	jmp	.generate_canary
	align	16
  ._make_struc_1:
	mov	[ecx], eax
	mov	[ecx+8], esi
	xor	eax, eax
	mov	[ecx+4], eax
	mov	[ecx+12], eax
	mov	[ecx+16], eax
	mov	[ecx+20], eax
	ret
	db	5 dup(0x90)
	align	16
  ._dup_handle_1:
	push	ecx
	mov	ecx, esp
	push	DUPLICATE_SAME_ACCESS
	push	FALSE
	push	0
	push	ecx
	push	dword [ebx]
	push	eax
	invoke	GetCurrentProcess
	push	eax
	call	[DuplicateHandle]
	pop	ecx
	test	eax, eax
	cmovnz	eax, ecx
	ret
	align	16

start.run_routine:
	; TODO: Thread-local storage?
	push	ebp
	mov	ebp, esp
	and	esp, -32
	call	.call_rout
	leave
	ret
	align	16

  .call_rout:
	mov	eax, eax	; 2-byte nop
	push	ebp
	mov	ebp, esp
	push	0
	push	_except_handlers
	push	dword [fs:0]
	lea	esp, [esp-0x2CC]
	stdcall _capture_ctx, esp
	sub	esp, 4*35
	xor	eax, eax
	mov	edi, esp
	mov	ecx, 35
	cld
	rep	stosd
	mov	[._ebp], ebp
	mov	eax, [ebp-12-sizeof.CONTEXT+0xB0]
	mov	ecx, [eax+4]
	lea	edx, [ebp-12]
	push	dword [thread_local.i] dword [ebp-12-sizeof.CONTEXT+0xAC] \
		dword [eax+4*2] ebx
	call	.call_rout_2
	mov	ebp, [._ebp]
	lea	esp, [ebp-12-sizeof.CONTEXT-4]
  .restore_reg:
	mov	ecx, [ebp-12]
	mov	[fs:0], ecx
  .restore_reg_noseh:
	pop	ecx
	xor	ecx, ebp
	xor	ecx, [start._canary]
	call	start._test_bufferoflw
	mov	ecx, esp
  .restore_reg_base:
	invoke	NtContinue, ecx, FALSE
	; NtContinue() may not returns
	mov	ebx, eax
	.repeat
		invoke	RtlRaiseStatus, ebx
	.until	0
	align	16

  .call_rout_2:
	push	ecx
	mov	[fs:0], edx
	irps	r, eax ecx edx ebx esi edi
	{
		xor	r, r
	}
	ret
	align	16

  ._hooked_exit:
	mov	ebp, [._ebp]
	lea	ecx, [ebp-12]
	call	_global_unwind
	mov	eax, [esp+4]
	lea	esp, [ebp-12-sizeof.CONTEXT-4]
	jmp	.restore_reg_noseh
	align	16

.SUBROUTINES .excpt_handler

.FUNC	b.warn
	cmp	edx, STATUS_BREAKPOINT
	mov	ecx, RVA _msg_breakpoint
	.CALL	warn_msg
	cmp	edx, STATUS_SINGLE_STEP
	mov	ecx, RVA _msg_breakpoint.int1
	.CALL	warn_msg
	mov	eax, 1
	ret
.ENDF
	align	16

.FUNC	warn_msg
	.if	ZERO?
		pop	eax
		call	_show_excpt_msg_ex.fromrva
		mov	eax, 1
	.endif
	rep_ret
.ENDF
	align	16

.FUNC	b.err
	.if	edx = STATUS_STACK_OVERFLOW
		push	ebp
		mov	ebp, esp
		call	.resetstkoflw.ex
		dec	eax
		and	eax, _libr.str_resetstkoflw
		mov	ecx, 0x3E9
		mov	edx, 0x120
		mov	[fs:0], ebx
		call	start.run_routine.show_excpt_msg_2
		mov	ecx, [esp+4+0xA8]
		mov	dword [ecx], esi
		push	.restore_reg_noseh
		ret
	.endif
	.if	edx = STATUS_STACK_BUFFER_OVERRUN
		call	start._test_bufferoflw.fail
	.endif
	mov	eax, 1
	ret
.ENDF

.END_SUBROUTINES
	align	16

  ._check_encoded_code_pointer:
	push	ebp
	mov	ebp, edx
	call	_my_decode_pointer
	mov	[ebp], eax
	sub	eax, _end_of_code
	sub	eax, (_begin_of_code - _end_of_code)
	pop	ebp
	ret
	align	16

  .resetstkoflw.ex:
	push	ecx edx eax
	mov	eax, [ebp+4*2]
	push	dword [eax]
	lea	edx, [eax-sizeof.CONTEXT-4]
	mov	[esp+4*3], edx
	_call_unwind eax, NULL, 0
	mov	eax, [esp+4*4]
	pop	ebx ebp esi esp
	push	eax

  .resetstkoflw:
	mov	eax, [start.proc_resetstkoflw]
	.if	eax
		call	eax
		neg	eax
		sbb	eax, eax
		neg	eax
	.endif
	rep_ret
	align	16

  .show_excpt_msg:
	xor	eax, eax
.SUBROUTINES .show_excpt_msg_2
	AlignProcEnter ,ebx esi edi, 0
	push	ecx
	sub	esp, 4*2
	mov	esi, eax
	imul	eax, edx, 3*sizeof.TCHAR
	sub	esp, eax
	and	esp, -16
	mov	ebx, esp
	mov	edi, edx
	invoke	FormatMessage,				\
		FORMAT_MESSAGE_IGNORE_INSERTS or	\
		FORMAT_MESSAGE_FROM_SYSTEM or		\
		FORMAT_MESSAGE_MAX_WIDTH_MASK,		\
		NULL, ecx, (1 shl 10), ebx, edx, NULL
	.if	eax
		test	esi, esi
		.MOV	eax, 1
		cmovz	eax, [MessageBoxEx]
		stdcall eax, HWND_DESKTOP, ebx, NULL, MB_ICONERROR, 0
	.endif
	AlignProcLeave
	ret
	align	16

.FUNC	1
	push	ebp
	invoke	GetModuleHandle, NULL
	lea	ebp, [ebx+edi*sizeof.TCHAR]
	invoke	LoadString, eax, 0, ebp, edi
	.if	eax
		push	esi ebx ebp edi
		_add_TCHAR ebp, edi
		push	ebp
		call	[sntprintf]
		add	esp, 4*5
		.if	eax < edi
			mov	[esp+4*3], ebp
		.endif
	.endif
	pop	ebp
	jmp	[MessageBoxEx]
.ENDF

.END_SUBROUTINES
	align	16

_show_excpt_msg_ex:
	push	ebp ebx esi ecx
	mov	ebx, ecx
  .endfromrva:
	or	ebp, -1
	invoke	GetModuleHandle, _libr.kernel32.dll
	test	eax, eax
	jz	.epilog1
	stdcall strgetproc, eax, _libr.str_check_dbg
	test	eax, eax
	jz	.epilog1
	mov	esi, eax
	push	esp
	call	[GetCurrentProcess]
	push	eax
	call	esi	; CheckRemoteDebuggerPresent( GetCurrentProcess(), pbDebuggerPresent )
	test	eax, eax
	jz	.epilog1
	mov	ebp, [esp]
	.if	ebp
		invoke	OutputDebugString, ebx
	.else
		invoke	MessageBox, HWND_DESKTOP, ebx, _msg_warning, MB_ICONWARNING
	.endif
  .epilog1:
	mov	eax, ebp
	pop	ecx esi ebx ebp
	ret
  .fromrva:
	push	ebp ebx esi ecx
	lea	ebx, [ecx+$-RVA $]
	jmp	.endfromrva
	align	16

_check_excpt_chain:
	; TRUE (1) = valid, FALSE (0) = invalid
	push	ebx esi edi
	mov	eax, [fs:0x18]
	mov	ebx, [eax+4]	; stack base (bottom)
	mov	edi, [eax+8]	; stack limit (top)
	sub	ebx, edi
	xor	eax, eax
	.BLOCK_BEGIN
	.repeat
		sub	edx, 1
		jc	BLOCK_END
		cmp	ecx, -1
		je	BLOCK_END
		mov	esi, ecx
		sub	esi, edi
		cmp	esi, ebx
		jae	.fail
		test	ecx, 3
		jnz	.fail
		mov	ecx, [ecx]
	.until	0
	.BLOCK_END
	inc	eax
  .fail:
	test	eax, eax
	pop	edi esi ebx
	ret
	align	16

_except_handlers:
	mov	eax, .t
	lea	ecx, [esp+4]
  .common:
	mov	edx, [ecx]
	test	dword [edx+4], 6
	jnz	.unwind_handler
	; exception handling
	AlignProcEnter ,ebx esi edi, 0
	push	ecx
	and	esp, -16
	mov	esi, [ecx+4]
	mov	ebx, [esi+4*2]
	cmp	ebx, [eax]
	jae	.abrt
	mov	edx, [edx]
	imul	ebx, 4*9
	lea	edi, [eax+ebx+4]
	mov	eax, edx
	shr	eax, 29
	mov	ebx, [edi+eax*4+4]
	mov	eax, 1
	.if	ebx
		mov	eax, [edi]
		mov	[esp], esi
		add	eax, esi
		call	ebx
	.endif
  .epilog1:
	AlignProcLeave
	ret
	align	4

  .abrt:
	; invalid function ID
	call	[abort]
	jmp	.epilog1
	align	16

  .unwind_handler:
	; stack unwinding
	mov	eax, 1
	ret

start._test_bufferoflw:
	test	ecx, ecx
	jnz	.fail
  .succ:
	rep_ret
  .preserve_eflags:
	jecxz	.succ
  .fail: ; __report_gsfailure
	AlignProcEnter ,ebx esi edi ecx, 0
	stdcall _capture_ctx, fatal_ctx
	mov	ecx, 0x502
	mov	edx, 0x120
	call	start.run_routine.show_excpt_msg
	xor	eax, eax
	mov	ebx, STATUS_STACK_BUFFER_OVERRUN
	lea	esi, [fatal_record]
	mov	dword [esi], ebx
	mov	dword [esi+8], eax
	mov	dword [esi+16], eax
	inc	eax
	mov	dword [esi+4], eax
	mov	eax,  [fatal_ctx+0xB8]
	mov	dword [esi+12], eax
	invoke	SetUnhandledExceptionFilter, NULL
	invoke	UnhandledExceptionFilter, fatal_excpt
	invoke	TerminateProcess, <invoke GetCurrentProcess>, ebx
	AlignProcLeave
	ret
	align	16

_capture_ctx:	; capturing registers
	dw	0xF7FF ; push edi
	mov	edi, [esp+4*2]
	mov	[edi+0xB0], eax
	mov	[edi+0xAC], ecx
	mov	[edi+0xA8], edx
	mov	[edi+0xA4], ebx
	mov	[edi+0xA0], esi
	push	eax
	mov	eax, [esp+4]
	mov	[edi+0x9C], eax
	mov	[edi+0xC8], ss
	mov	[edi+0xBC], cs
	mov	[edi+0x98], ds
	mov	[edi+0x94], es
	mov	[edi+0x90], fs
	mov	[edi+0x8C], gs
	pushf
	pop	dword [edi+0xC0]
	mov	eax, [ebp+4]
	mov	[edi+0xB8], eax
	mov	eax, [ebp]
	mov	[edi+0xB4], eax
	lea	eax, [ebp+8]
	mov	[edi+0xC4], eax
	mov	eax, ebp
	xor	eax, [start._canary]
	mov	[esp+4*3], eax
	mov	dword [edi], 0x10007
	pop	eax
	pop	edi
	ret
	align	16

_global_unwind:
	push	ebp ebx esi edi
	_call_unwind ecx, NULL, 0
	pop	edi esi ebx ebp
	ret
	align	16

start.generate_canary:
	push	ebp ebx esi edi ; for unwind
	xor	ebp, ebp
	push	ecx ecx ebp .excpt1a
	push	dword [fs:ebp]	; actually is [fs:0]
	mov	[fs:ebp], esp
	cmp	[ecx], ebp
	jnz	.succ
  .rdtsc_begin:
	rdtsc
	imul	ecx, eax, -446974657	; pseudo random
	xor	ecx, edx
	jz	.rdtsc_begin
  .rdtsc_end:
	mov	eax, [esp+4*3]
	mov	[eax], ecx
  .succ:
	xor	eax, eax
	inc	eax
	jmp	.epilog1
  .excpt1b:
	sub	ecx, .rdtsc_begin
	.if	ecx < (.rdtsc_end - .rdtsc_begin)
		mov	eax, [esp+4*3]
		xor	ecx, ecx
		mov	[eax], ecx
	.endif
  .fail:
	xor	eax, eax
  .epilog1:
	pop	dword [fs:0]
	add	esp, 4*4
	pop	edi esi ebx ebp
	ret
	align	16
  .excpt1a:	; if time stamp is disabled or access violation
	push	ebx esi
	mov	eax, [esp+4*3]
	mov	ecx, [eax+4]
	test	ecx, 0x6
	.if	~ZERO?
		mov	eax, 1
		pop	esi ebx
		ret
	.endif
	mov	ebx, [esp+4*4]
	mov	ecx, [eax]
	mov	[ebx+4*4], ecx
	mov	ecx, [esp+4*5]
	mov	esi, [ecx+0xB8]
	mov	ecx, ebx
	call	_global_unwind
	mov	esp, ebx
	mov	ecx, esi
	; call	__NLG_Notify
	jmp	.excpt1b
	align	16

_check_cpuid:
	pushf
	pushf
	pop	edx
	mov	eax, edx
	xor	edx, 1 shl 21
	push	edx
	popf
	pushf
	pop	edx
	popf
	xor	eax, edx
	and	eax, 1 shl 21
	neg	eax
	sbb	eax, eax
	neg	eax
	ret
	align	16

MessageBoxStub:
	mov	ecx, _libr.str_MessageBox
	call	_mygetlib.user32
	mov	edx, .fail
	test	eax, eax
	mov	ecx, eax
	cmovz	ecx, edx
	mov	eax, MessageBoxStub
	lock	cmpxchg [MessageBoxStubAddr], ecx
	cmovz	eax, ecx
	jmp	eax
  .fail:
	xor	eax, eax
	ret
	align	16

_my_encode_pointer:	; FASTCALL (acts like EncodeSystemPointer)
	mov	eax, ecx
	mov	edx, [start._canary]
	mov	cl, dl
	and	cl, 0x1F
	xor	eax, edx
	ror	eax, cl
	ret
	align	16

_my_decode_pointer:	; FASTCALL (acts like DecodeSystemPointer)
	mov	eax, ecx
	mov	edx, [start._canary]
	mov	cl, dl
	and	cl, 0x1F
	rol	eax, cl
	xor	eax, edx
	ret
	align	16

_make_identifier:
	; expect DF is cleared
	push	ebx esi edi
	mov	ebx, base36_c
	lea	esi, [edx+4]
	mov	edi, ecx
	mov	ecx, [edx]
	call	.1b
	mov	ecx, esi
	call	.1
	and	type.TCHAR [edi], 0
	mov	eax, edi
	pop	edi esi ebx
	ret
	align	16
  .1:	; uses EBX and EDI, also clears ECX
	mov	edx, [ecx+4]
	push	edx
	mov	ecx, [ecx]
	call	.1a
	pop	ecx
	jmp	.1b
	align	16
  .1a:
	mov	eax, 3
	and	eax, ecx
	mov	al, [ebx+eax+0x20]
	stost
	shr	ecx, 2
	test	edx, edx
	jnz	.1c
  .1b:
	.if	ecx
		.repeat
			mov	al, cl
			and	eax, 0x1F
			xlatb
			stost
			shr	ecx, 5
		.until	ZERO?
	.endif
	rep_ret
  .1c:
	mov	dl, 6
	.repeat
		mov	al, cl
		and	eax, 0x1F
		xlatb
		stost
		shr	ecx, 5
		dec	dl
	.until	ZERO?
	rep_ret
	align	16
  ._base:
	call	[GetCurrentProcessId]
	push	4
	pop	ecx
	xadd	[esp+4], ecx
	mov	[ecx], eax
	; QueryPerformanceCounter always succeed and return non-zero
	jmp	[QueryPerformanceCounter]
	align	16

_mygetlib:
	xor	ecx, ecx
	jmp	.ex
	align	16
  .user32:
	lea	eax, [_libr.user32.dll]
	lea	edx, [start.modul.user32]
	jmp	.ex
	align	16
  .msvcrt:
	lea	eax, [_libr.msvcrt.dll]
	lea	edx, [start.modul.msvcrt]
	jmp	.ex
	align	16
  .dbghelp:
	lea	eax, [_libr.dbghelp.dll]
	lea	edx, [start.modul.dbghelp]
  .ex:
	push	esi edi ecx
	mov	ecx, vSyncDllEvent
	push	ecx ecx
	mov	esi, eax
	mov	edi, edx
	call	[EnterCriticalSection]
	mov	eax, [edi]
	.if	~eax
		invoke	LoadLibrary, esi
		mov	[edi], eax
	.endif
	mov	ecx, [esp+4]
	.if	eax & ecx
		stdcall strgetproc, eax, ecx
	.endif
	mov	esi, eax
	call	[LeaveCriticalSection]
	mov	eax, esi
	test	eax, eax
	pop	ecx edi esi
	ret
	align	16

_fMap:	; FASTCALL with cleanup by caller
	; return flags: CF, ZF
	AlignProcEnter ,ebx esi edi, 0
	push	eax
	xor	ebx, ebx
	mov	esi, edx
	mov	edi, ecx
	invoke	CreateFileMapping, INVALID_HANDLE_VALUE,\
		ebx, PAGE_READWRITE, ebx, edx, dword [ebp+4*2]
	push	eax
	invoke	GetLastError
	cmp	dword [esp], ebx
	je	.1a
	cmp	eax, 0xB7
	je	.1b
	push	esi				; dwNumberOfBytesToMap
	push	ebx				; dwFileOffsetLow	= 0
	push	ebx				; dwFileOffsetHigh	= 0
	push	FILE_MAP_READ or FILE_MAP_WRITE ; dwDesiredAccess
	push	dword [local_fp-4*2]		; hFileMappingObject
	inc	ebx
	call	[MapViewOfFile]
	test	eax, eax
	jz	.1b
	pop	dword [edi]
	mov	[edi+4], eax
	.rem@AlignProcLeave
	ret
	align	16
  .1a:
	cmp	eax, 6	; 6 means ERROR_INVALID_HANDLE
	sete	bl
	jmp	.1c
  .1b:
	xor	bl, 1
	call	[CloseHandle]
  .1c:
	mov	eax, [local_fp-4]
	.if	eax
		add	[eax+4], ebx
		adc	dword [eax+8], 0
	.endif
	shr	bl, 1
  .zero:
	xor	eax, eax
	AlignProcLeave
	ret
	align	16

_fUnmap:
	push	ebx
	mov	ebx, [ecx]
	.if	ebx
		invoke	UnmapViewOfFile, dword [ecx+4]
		invoke	CloseHandle, ebx
	.endif
	pop	ebx
	ret
	align	16

_splitcmdline2module:
	push	ebp
	mov	ebp, esp
	push	ebx esi edi ecx 0 0x1000 HEAP_NO_SERIALIZE
	mov	edi, edx
	mov	eax, ' '
	or	ecx, -1
	repe	scast
	call	[HeapCreate]
	test	eax, eax
	jz	.epilog1d
	sub	esp, 4*12
	and	esp, -16
	mov	[ebp-4*8], eax
	lea	ebx, [esp+4*4]
	_dec_TCHAR edi
	mov	[ebx], edi
	call	.1a
	test	eax, eax
	jz	.epilog1c
	mov	[ebp-4*5], eax
	lea	ecx, [esp+4*5]
	lea	edx, [ebp-4*7]
	call	.getlibproc1a
	jz	.epilog1b
	invoke	HeapDestroy, dword [ebp-4*8]
	lea	esp, [ebp-4*7]
	pop	eax edx ecx
	jmp	.epilog1e
	align	16
  .epilog1b:
	mov	eax, [ebp-4*5]
	mov	[esp], eax
	call	[free]
  .epilog1c:
	invoke	HeapDestroy, dword [ebp-4*8]
  .epilog1d:
	lea	esp, [ebp-4*4]
	xor	eax, eax
	xor	ecx, ecx
	xor	edx, edx
  .epilog1e:
	pop	ebx
	mov	[ebx], eax
	mov	[ebx+4], edx
	mov	[ebx+4*2], ecx
	test	eax, eax
	pop	edi esi ebx ebp
	ret
	align	16
  .1a:
	mov	[esp+4], eax
	mov	[esp+4*2], ebx
	push	ebp
	mov	ebp, esp
	sub	esp, 4*2
	xor	ebx, ebx
	call	.get_next
	mov	eax, 4
	mov	ebx, 3
	call	.get_next
	mov	[ebx+4*3], eax
	mov	eax, 4*2
	mov	ebx, 2
	call	.get_next
	mov	eax, [ebx]
	leave
	mov	[esp+4], eax
	jmp	[strdup]
  .heapop_return:
	xor	eax, eax
	leave
	ret
	align	16

  .heapalloc1:
	invoke	HeapAlloc, dword [ebp+4*2], 0, eax
	test	eax, eax
	jz	.heapop_return
	rep_ret
  .heapfindsep1:
	.if	~ZERO?
		mov	edx, _my_separators
		push	ecx edx ecx
		call	[tcspbrk]
		jmp	@f
	.endif
	mov	edx, ' '
  .heapstrchr1:
	push	ecx edx ecx
	call	[tcschr]
  @@:
	add	esp, 4*2
	.if	~eax
		call	[tcslen]
		pop	ecx
		test	eax, eax
		jz	.heapop_return
		if (sizeof.TCHAR > 1)
			lea	eax, [eax * sizeof.TCHAR]
		end if
  @@:		rep_ret
	.endif
	pop	ecx
	sub	eax, ecx
	jz	.heapop_return
	rep_ret
	align	16

  .getlibproc1a:
	AlignProcEnter ,ebx esi edi, 0
	mov	esi, ecx
	mov	ebx, edx
	invoke	LoadLibrary, dword [esi]
	.BLOCK_BEGIN
	.if	eax
		mov	edi, eax
		stdcall strgetproc, edi, dword [esi+4]
		.if	~eax
			invoke	FreeLibrary, edi
			xor	eax, eax
			jmp	BLOCK_END
		.endif
		.if	dword [esi+4*2] & (edi <> ($ - rva $))
			push	eax
			mov	eax, edi
			mov	edx, ._proc_addrs
			call	._get_iat.iat_hook
			pop	eax
		.endif
		mov	[ebx], edi
		mov	[ebx+4], eax
	.endif
	test	eax, eax
	.BLOCK_END
	AlignProcLeave
	ret
	align	16
  ._proc_addrs.replaced:
	push	dword [esp+4*2] dword [esp+4*2]
	call	[GetProcAddress]
	.if	eax
		lea	edx, [._proc_addrs.krnl32+4]
		mov	ecx, [edx-4]
		.repeat
			.if	eax = [edx]
				mov	eax, [edx+4]
				ret	4*2
			.endif
			add	edx, 4*2
		._until ecx
	.endif
	ret	4*2
	align	4
  ._release1:
	push	dword [ecx+8]
	mov	eax, [ecx]
	.if	eax
		invoke	FreeLibrary, eax
	.endif
	call	[free]
	pop	ecx
	ret
	align	16

  .get_next:
	; expected DF is cleared.
	; ebx = flags
	; 0x20	= ' '
	; 0x22	= '"'
	; 0x2C	= ','
	mov	[esp+4], eax
	mov	[esp+4*2], ebx
	mov	eax, [ebp+4*3]
	and	ebx, 1
	mov	esi, [eax]
	mov	ecx, esi
	cmp	byte [esi], '"'
	jz	.get_next.1c
	test	ebx, ebx
	call	.heapfindsep1
	lea	edi, [esi+eax]
  .get_next.1c_:
	push	0 eax esi
  .get_next.1a:
	mov	eax, ' '
	or	ecx, -1
	repe	scast
	movzx	eax, type.TCHAR [edi-sizeof.TCHAR]
	dec	ebx
	js	.get_next.1b
	sub	eax, ','
	jz	.get_next.1a
	dec	eax
	jz	.get_next.1d
  .get_next.1b:
	_dec_TCHAR edi
	mov	ebx, [ebp+4*3]
	mov	[ebx], edi
	test	byte [esp+4*5], 2
	jz	.get_next.1e
	mov	edi, [esp+4]
	lea	eax, [edi+sizeof.TCHAR]
	call	.heapalloc1
	and	type.TCHAR [eax+edi], 0
	push	eax
	call	[memcpy]
	add	esp, 4*3
	mov	ecx, [esp+4*2]
	mov	[ebx+ecx], eax
	pop	eax
	ret
	align	16

  .get_next.1c:
	_inc_TCHAR ecx
	_inc_TCHAR esi
	mov	edx, '"'
	call	.heapstrchr1
	xor	ecx, ecx
	lea	edi, [esi+eax]
	cmp	type.TCHAR [edi], '"'
	sete	cl
	_add_TCHAR edi, ecx
	jmp	.get_next.1c_
  .get_next.1d:
	movzx	eax, type.TCHAR [edi]
	.if	eax <> 'H'
		cmp	eax, '-'
		jne	.get_next.1b
		push	ebx ebp
		ud2
	.endif
	movzx	ecx, type.TCHAR [edi+sizeof.TCHAR]
	and	ecx, not 0x20
	je	.get_next.1b
	_inc_TCHAR edi
	or	byte [esp+4*2], 1
	jmp	.get_next.1a
  .get_next.1e:
	add	esp, 4*3
	ret
	align	16

_splitcmdline2module._get_iat:
	xor	ecx, ecx
  .hook:
	push	ebx esi edi 0 eax eax edx
	mov	ebx, ecx
	lea	ecx, [esp+4*3]
	invoke	RtlImageDirectoryEntryToData, eax, TRUE, 1, ecx
	mov	[esp+4*2], eax
	.if	eax & ebx
		call	@f
	.endif
	add	esp, 4*2
	pop	eax ecx edi esi ebx
	ret
  @@:
	push	ebp
	mov	ebp, esp
	jmp	ebx
	align	16

include 'myiathook.inc'
	align	16

_newproc:
	AlignProcEnter ,ebx esi edi, 0
	setc	bl
	sub	esp, 68
	mov	esi, ecx
	mov	edi, esp
	mov	ecx, 68 / 4
	xor	eax, eax
	rep	stosd
	mov	eax, esp
	neg	bl
	sbb	ecx, ecx
	and	ecx, CREATE_SUSPENDED
	mov	edi, edx
	invoke	CreateProcess, NULL, esi, NULL, NULL, FALSE, ecx, NULL, NULL, eax, edi
	test	eax, eax
	mov	edx, edi
	.if	ZERO?
		mov	ecx, 4
		rep	stosd
	.endif
	AlignProcLeave
	ret
	align	16

_closehandles:
	push	ebx esi
	pushf
	cld
	mov	esi, ecx
	mov	ebx, edx
	.repeat
		lodsd
		.if	eax
			invoke	CloseHandle, eax
		.endif
	._until ebx
	popf
	pop	esi ebx
	ret
	align	16

_waitforalerted:
	; 0x00000000 = WAIT_OBJECT_0
	; 0x000000C0 = WAIT_IO_COMPLETION
	; 0x00000101 = STATUS_ALERTED
	; 0x00000102 = WAIT_TIMEOUT
	.repeat
		invoke	NtWaitForSingleObject, ebp, TRUE, NULL
	.until	eax <> 0x102
	test	eax, eax
	; ZF = 1 means terminated
	; SF = 1 means failure
	ret
	align	4
  .1:
	push	ebp ebx ecx
	mov	ebp, edx
	mov	ebx, ecx
	push	esp ebp
	call	[NtResumeThread]
	test	eax, eax
	js	.resume_fail
  .1b:
	call	_waitforalerted
	js	.resume_fail
	lea	ecx, [eax-0x101]
	mov	edx, [ebx]
	neg	ecx
	dec	edx
	ja	.1b
	cmc
	sbb	ecx, ecx
	test	eax, ecx
  .1a:
	pop	ecx ebx ebp
	ret
	align	4
  .resume_fail:
	stc
	jmp	.1a
	align	4
  .abrt:
	call	[abort]
  _no_return:
	int3
	jmp	_no_return
	align	16

strgetproc:
	if __iswidechar
		jmp	wcsgetproc
	else
		jmp	[GetProcAddress]
	end if
	align	16
wcsgetproc:
	AlignProcEnter ,ebx esi edi, 0
	mov	edi, [ebp+4*3]
	.if	edi <= 0xFFFF
		push	NULL edi
		jmp	.findord1
	.endif
	or	ecx, -1
	xor	eax, eax
	cld
	mov	esi, edi
	repnz	scasw
	not	ecx
	mov	ebx, ecx
	push	ecx
	call	[malloc]
	test	eax, eax
	jz	.no_enough_memory
	mov	[esp], eax
	mov	edi, eax
	.repeat
		lodsw
		test	ah, ah
		jnz	.not_in_ascii
		stosb
	._until ebx
	push	dword [local_fp-4]
  .findord1:
	push	dword [ebp+4*2]
	call	[GetProcAddress]
	mov	ebx, eax
	call	[free]
	mov	eax, ebx
  .epilog1:
	AlignProcLeave
	ret	8
	align	16
  .no_enough_memory:
	push	8
	jmp	.fail1
  .not_in_ascii:
	call	[free]
	push	127
  .fail1:
	call	[SetLastError]
	xor	eax, eax
	jmp	.epilog1
	align	16

_my_chkstk:
	push	eax ecx
	mov	ecx, esp
	sub	ecx, eax
	lea	eax, [esp-0x1000]
	.while	eax > ecx
		or	dword [eax], 0
		sub	eax, 0x1000
	.endw
	or	dword [ecx], 0
	pop	ecx eax
	ret
	align	16

_end_of_code:

section '.data' data readable writeable
	start._canary		rd 1
	start._canary_2 	dd 0xBB40E64E
	start._stack_pointer	rd 1
	MessageBoxStubAddr	dd MessageBoxStub
	align	 16
	start.modul.dbghelp	rd 2
	start.modul.msvcrt	rd 2
	start.modul.user32	rd 2
	start.proc_resetstkoflw dd NULL
	align	 16
	start.run_routine._ebp	dd NULL
	align	 16
	fatal_excpt	dd fatal_record, fatal_ctx
	fatal_record	rd 20
	fatal_ctx	rd sizeof.CONTEXT/4
	align	 16
	vSyncDllEvent	rd 6
	align	 16
	_dbg_ImageDirectoryEntryToData	dd NULL
	align	 16
	_splitcmdline2module._proc_addrs:
		dd     _libr.kernel32.dll
		dd     .krnl32
	.krnl32 dd     0x80000000 + 2
		dd     RVA ExitProcess, start.run_routine._hooked_exit
		dd     RVA .replaced
		rd     24

thread_local:
	data 9
	   dd 0, 0, .i, .c, 0, 0
	.i dd -1
	.c dd 0
	end data

section '.rdata' data readable
	start._string_MYCON	TCHAR "MYCON_", 0
	align	16
	_myconhost_exe__s	TCHAR """myconhost.exe"" %s", 0
	base36_c		db "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0
	align	4

	_except_handlers.t dd 1
	start.run_routine.excpt_handler.b:
		dd 12, NULL, NULL, NULL, NULL, .warn, NULL, .err, NULL

	_libr.dbghelp.dll	TCHAR "dbghelp.dll", 0
	_libr.kernel32.dll	TCHAR "kernel32.dll", 0
	_libr.msvcrt.dll	TCHAR "msvcrt.dll", 0
	_libr.user32.dll	TCHAR "user32.dll", 0
	_libr.str_resetstkoflw	TCHAR '_resetstkoflw', 0
	_libr.str_MessageBox	TCHAR 'MessageBox', _API_SUFFIX, 0
	_libr.str_ImageDirectoryEntryToData \
				TCHAR 'ImageDirectoryEntryToData', 0
	_libr.str_check_dbg	TCHAR 'CheckRemoteDebuggerPresent', 0
	_msg_breakpoint 	TCHAR 'STATUS_BREAKPOINT encountered', 0
		.int1		TCHAR 'STATUS_SINGLE_STEP encountered', 0
	_msg_warning		TCHAR 'Warning', 0
	_my_separators		TCHAR ' ,', 0
	align	16

	data 10
		dd 0x48
		dd 14 dup(0)
		dd start._canary_2
	end data
	dd handler_table, 2

handler_table:
	dd RVA _except_handlers
	dd RVA start.generate_canary.excpt1a
	dd 0

section '.idata' import data readable writeable

  library kernel32,'KERNEL32.DLL',\
	  msvcrt,  'MSVCRT.DLL',\
	  ntdll,   'NTDLL.DLL',\
	  user32,  'USER32.DLL'

  include 'api/kernel32.inc'
  include 'api/user32.inc'

  import ntdll,\
	 LdrLockLoaderLock, 'LdrLockLoaderLock',\
	 LdrUnlockLoaderLock, 'LdrUnlockLoaderLock',\
	 NtContinue, 'NtContinue',\
	 NtDelayExecution, 'NtDelayExecution',\
	 NtRaiseException, 'NtRaiseException',\
	 NtResumeThread, 'NtResumeThread',\
	 NtTerminateProcess, 'NtTerminateProcess',\
	 NtTestAlert, 'NtTestAlert',\
	 NtWaitForSingleObject, 'NtWaitForSingleObject',\
	 RtlCaptureContext, 'RtlCaptureContext',\
	 RtlImageDirectoryEntryToData, 'RtlImageDirectoryEntryToData',\
	 RtlRaiseStatus, 'RtlRaiseStatus',\
	 RtlUnhandledExceptionFilter, 'RtlUnhandledExceptionFilter'
	 ; RtlUnwind, 'RtlUnwind'

  import msvcrt,\
	 abort, 'abort',\
	 free, 'free',\
	 malloc, 'malloc',\
	 memcpy, 'memcpy',\
	 memicmp, '_memicmp',\
	 qsort, 'qsort',\
	 setjmp, '_setjmp',\
	 snprintf, '_snprintf',\
	 snwprintf, '_snwprintf',\
	 strchr, 'strchr',\
	 strdup, '_strdup',\
	 strlen, 'strlen',\
	 strncpy, 'strncpy',\
	 strpbrk, 'strpbrk',\
	 wcschr, 'wcschr',\
	 wcsdup, '_wcsdup',\
	 wcslen, 'wcslen',\
	 wcsncpy, 'wcsncpy',\
	 wcspbrk, 'wcspbrk'

  ; Why no CommandLineToArgvA function?

; section '.tls' code readable writable

section '.rsrc' resource data readable

  directory RT_STRING, dir_strings

  resource  dir_strings,\
	    1, LANG_ENGLISH+SUBLANG_DEFAULT, res_strings_en,\
	    1, LANG_CHINESE+SUBLANG_CHINESE_SIMPLIFIED, res_strings_zh_cn

; STRINGTABLE with id = 1 can have STRINGS with ids between 0-15
  resdata res_strings_en
    du 16, "%s (%s failure)", 0
    du 15 dup(0)
  endres

  resdata res_strings_zh_cn
    du 11, "%s (%s 失败)", 0
    du 15 dup(0)
  endres

include 'reloc_table.inc'